package com.scheduling.schedule.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.scheduling.common.exception.BusinessException;
import com.scheduling.product.entity.Operation;
import com.scheduling.product.mapper.OperationMapper;
import com.scheduling.schedule.service.OperationScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 * 工序排产服务实现类
 *
 * @author 开发团队
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OperationScheduleServiceImpl implements OperationScheduleService {

    private final OperationMapper operationMapper;

    @Override
    public List<Operation> getOperationsByProductId(String productId) {
        log.debug("根据产品ID查询工艺路线的所有工序：{}", productId);

        if (StrUtil.isBlank(productId)) {
            throw new BusinessException("产品ID不能为空");
        }

        List<Operation> operations = operationMapper.selectOperationsByProductId(productId);
        log.debug("产品 {} 的工序列表：{}", productId,
                operations.stream().map(Operation::getOperationId).toArray());

        return operations;
    }

    @Override
    public Operation getOperationById(String operationId) {
        log.debug("根据工序ID查询工序详情：{}", operationId);

        if (StrUtil.isBlank(operationId)) {
            throw new BusinessException("工序ID不能为空");
        }

        Operation operation = operationMapper.selectById(operationId);
        if (operation == null) {
            throw new BusinessException("工序不存在: " + operationId);
        }

        return operation;
    }

    @Override
    public List<String> getCompatibleMachines(String operationId) {
        log.debug("根据工序ID查询兼容的机器列表：{}", operationId);

        if (StrUtil.isBlank(operationId)) {
            throw new BusinessException("工序ID不能为空");
        }

        Operation operation = getOperationById(operationId);

        // 根据工序要求的机器类型查询空闲机器
        List<String> machines = getIdleMachinesByType(operation.getMachineTypeId());
        log.debug("工序 {} 兼容的机器列表：{}", operationId, machines);

        return machines;
    }

    @Override
    public List<String> getPredecessorOperations(String operationId) {
        log.debug("检查工序依赖关系：{}", operationId);

        if (StrUtil.isBlank(operationId)) {
            throw new BusinessException("工序ID不能为空");
        }

        Operation operation = getOperationById(operationId);
        String predecessorOps = operation.getPredecessorOps();

        if (StrUtil.isBlank(predecessorOps)) {
            return CollUtil.newArrayList();
        }

        List<String> predecessors = StrUtil.split(predecessorOps, ',');
        log.debug("工序 {} 的前置工序：{}", operationId, predecessors);

        return predecessors;
    }

    @Override
    public List<String> getIdleMachinesByType(String machineTypeId) {
        log.debug("根据机器类型ID查询空闲机器：{}", machineTypeId);

        if (StrUtil.isBlank(machineTypeId)) {
            throw new BusinessException("机器类型ID不能为空");
        }

        List<String> machines = operationMapper.selectIdleMachinesByType(machineTypeId);
        log.debug("机器类型 {} 的空闲机器：{}", machineTypeId, machines);

        return machines;
    }

    @Override
    public boolean canStartOperation(String operationId, List<String> completedOperations) {
        log.debug("检查工序 {} 是否可以开始，已完成工序：{}", operationId, completedOperations);

        List<String> predecessors = getPredecessorOperations(operationId);

        // 如果没有前置工序，可以直接开始
        if (CollUtil.isEmpty(predecessors)) {
            return true;
        }

        // 检查所有前置工序是否都已完成
        for (String predecessor : predecessors) {
            if (completedOperations == null || !completedOperations.contains(predecessor)) {
                log.debug("工序 {} 的前置工序 {} 尚未完成", operationId, predecessor);
                return false;
            }
        }

        log.debug("工序 {} 的所有前置工序都已完成，可以开始", operationId);
        return true;
    }

    /**
     * 按工序依赖关系排序工序列表
     */
    @Override
    public void sortOperations(List<Operation> operations) {
        if (operations == null || operations.isEmpty()) return;

        // 工序ID到深度的映射
        Map<String, Integer> depthMap = new HashMap<>();

        // 初始队列：无前置工序的工序深度为0
        Queue<Operation> queue = new ArrayDeque<>();
        for (Operation op : operations) {
            String predOps = op.getPredecessorOps();
            if (predOps == null || predOps.trim().isEmpty()) {
                depthMap.put(op.getOperationId(), 0);
                queue.offer(op);  // 加入处理队列
            } else {
                depthMap.put(op.getOperationId(), -1); // 深度未知
            }
        }

        // 广度优先计算深度
        while (!queue.isEmpty()) {
            Operation current = queue.poll();
            String currentId = current.getOperationId();
            int currentDepth = depthMap.get(currentId);

            // 查找依赖于当前工序的所有工序
            for (Operation op : operations) {
                if (depthMap.get(op.getOperationId()) != -1) continue; // 已计算深度

                String predOps = op.getPredecessorOps();
                if (predOps == null || predOps.isEmpty()) continue;

                // 检查当前工序是否是该工序的前置
                boolean hasDependency = false;
                for (String predId : predOps.split(",")) {
                    if (currentId.equals(predId.trim())) {
                        hasDependency = true;
                        break;
                    }
                }

                if (!hasDependency) continue;

                // 检查前置是否全部计算完毕
                boolean allKnown = true;
                int maxDepth = -1;
                for (String predId : predOps.split(",")) {
                    String id = predId.trim();
                    if (id.isEmpty()) continue;

                    Integer depth = depthMap.get(id);
                    if (depth == null || depth == -1) {
                        allKnown = false;
                        break;
                    }
                    if (depth > maxDepth) maxDepth = depth;
                }

                // 计算新工序深度
                if (allKnown) {
                    int newDepth = maxDepth + 1;
                    depthMap.put(op.getOperationId(), newDepth);
                    queue.offer(op);
                }
            }
        }

        // 按深度排序
        operations.sort(Comparator.comparingInt(
                op -> depthMap.get(op.getOperationId())
        ));
    }

} 